/**********************************************
*  Classes:   GLRenderer
*  Desc:      Renders a scene graph using OpenGL.
*			  Singleton class. Inherits from CdnRenderer
*  Author:    Vaios Kalpias-Ilias (C) 2008-2009
***********************************************/

#ifndef GLRENDERER_H
#define GLRENDERER_H

#include "CdnRenderer.h"
#include <map>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <gl/glaux.h>
#include "glext.h"

class Light;
SmartPointer(Light);

class GLRenderer : public CdnRenderer
{
	friend class CdnRenderer;

public:

	//static GLRenderer* GetInstance();
	//static void Destroy();

	// initialize renderer
	bool Init(HINSTANCE &hInstance, 
		bool fullscreen = false,
		int width = 1024,
		int height = 768,
		const char* title = "CodenWindow");
	
	// render a scene graph
	void RenderScene (SceneNode* scene);
	// creates vertices, normals etc for a node
	bool BindNodeToMesh(GeometryNode* node,
					mth::Vector3* vertices,
					mth::Vector3* normals,
					mth::Vector2* texCoords,
					int numOfVertices);

	// gets a texture id
	unsigned int GetNewTextureId() 
	{
		unsigned int id;
		glGenTextures(1, &id);
		return id;
	}

	// sets skybox
	void SetSkyBox (SkyBoxPtr skyBox);

	// sets a texture's environment state
	void SetTextureEnvState(unsigned int texId,
		TextureProperty::EnvironmentState state);

	// resizes window
	void ResizeWindow(int width, int height);

	// deletes vbo's
	void UnloadGeometry();

private:

	typedef std::list <GeometryNode*> GeometryList;
	typedef std::map <unsigned int, GeometryList*> GeometryMap;
	typedef std::map <MaterialProperty*, GeometryMap*> MaterialMap;
	typedef std::map <TextureProperty*, MaterialMap* > TexturesMap;

	// struct used to render vbo's
	typedef struct render_t
	{
		unsigned int verticesName;
		unsigned int normalsName;
		unsigned int texCoordsName;
		unsigned int numOfVertices;

		render_t()
			: verticesName(0),
			normalsName(0),
			texCoordsName(0),
			numOfVertices(0)
		{}

		render_t(unsigned int vertName,
			unsigned int normName,
			unsigned int texName,
			unsigned int num)
			: verticesName(vertName),
			normalsName(normName),
			texCoordsName(texName),
			numOfVertices(num)
		{}

	} RenderStruct;

	// list of renderstructs to be rendered
	typedef std::list<RenderStruct*> RenderList;
	RenderList m_lRenderStructs;
	
	// sorted geometry
	TexturesMap m_SortedGeometry;

	// skybox display list
	unsigned int m_uiSkyBoxDL;

	// Permanent Rendering Context
	HGLRC		m_hRC;		 
	

	GLRenderer();
	~GLRenderer();

	// creates an OpenGL window
	bool CreateRendererWindow(HINSTANCE &hInstance, 
		                      bool fullscreen,
							  int width,
							  int height,
							  const char* title);
	// destroys window
	void DestroyRenderWindow();
	// sorts scene by states
	void SortScene(SceneNode* scene);
	// rendered sorted geometry
	void RenderSorted();
	// clears sorted geometry
	void ClearSorted();
	// enable vertices
	void EnableVertices(GeometryNode* node);
	// disable vertices
	void DisableVertices(GeometryNode* node);
	// enable normals
	void EnableNormals(GeometryNode* node);
	// disable normals
	void DisableNormals(GeometryNode* node);
	// enable texture coords
	void EnableTexCoords(GeometryNode* node);
	// disable tex coords
	void DisableTexCoords(GeometryNode* node);
	// enable textures
	void EnableTextures(TextureProperty* tex);
	// enable material
	void EnableMaterial(MaterialProperty* mat);
	// enables all lights for a node
	void EnableLights(GeometryNode* node);
	// enables one of 8 lights
	void EnableLight(LightPtr light, unsigned int num);
	// disables lights
	void DisableLights();
	// show bounding boxes
	void ShowBoundingBoxes(GeometryNode* node);
	// are VBO's suuported?
	static bool IsVBOExtensionSupported();
	// VBO Extension Function Pointers
	// VBO Name Generation Procedure
	PFNGLGENBUFFERSARBPROC glGenBuffersARB;	
	// VBO Bind Procedure
	PFNGLBINDBUFFERARBPROC glBindBufferARB;			
	// VBO Data Loading Procedure
	PFNGLBUFFERDATAARBPROC glBufferDataARB;		
	// VBO Deletion Procedure
	PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB;

	
};

#endif